﻿/*
 * stringref.cpp
 *
 *  Created on: 2016年12月12日
 *      Author: Dylan.Gao
 */

#include <dm/export.hpp>
#define DM_API_STRING DM_API_EXPORT

#include <dm/string/stringref.hpp>
#include <cstring>
#include <cstdlib>

namespace dm{
namespace string{

/**
 * 比较是否相同内容。
 * 要求每个字符都相同。
 * @param str
 * @return 是否相同
 */
bool CStringRef::operator ==( const CStringRef& str )const{
	int l = len();
	if( l==str.len() ){
		for( int i=0;i<l;++i )
			if( m_r[i]!=str.m_r[i] )
				return false;
		return true;
	}
	return false;
}

/**
 * 比较字符串大小
 * @param str
 * @return
 */
bool CStringRef::operator>( const CStringRef& str )const{
	int l = len();
	int sl = str.len();
	int s = l>sl?sl:l;

	for( int i=0;i<s;++i ){
		if( m_r[i]>str.m_r[i] )
			return true;
		else if( m_r[i]<str.m_r[i] )
			return false;
	}

	return l>sl;
}

bool CStringRef::operator>=( const CStringRef& str )const{
	int l = len();
	int sl = str.len();
	int s = l>sl?sl:l;

	for( int i=0;i<s;++i ){
		if( m_r[i]>str.m_r[i] )
			return true;
		else if( m_r[i]<str.m_r[i] )
			return false;
	}

	return l>=sl;
}

/**
 * 字符长度
 * @return
 * - -1 字符串为空
 */
int CStringRef::len()const{
	if( m_r==NULL )
		return 0;
	int l = 0;
	while( m_r[l]!='\0' )
		++l;
	return l;
}

/**
 * 转换成Uint8
 * @param ok 是否成功。NULL不需要返回
 * @return
 */
dm::uint8 CStringRef::toUint8( bool* ok )const{
	dm::uint8 rt = 0;
	// 0~255
	if( len()>0 && len()<=3 ){
		if( isNum() ){
			int iValue = std::atoi(m_r);
			if( iValue>=0 && iValue<=255 ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

dm::int8 CStringRef::toInt8(  bool* ok )const{
	dm::int8 rt = 0;
	// -128~127
	if( len()>0 && len()<=4 ){
		if( isNum() ){
			int iValue = std::atoi(m_r);
			if( iValue>=-128 && iValue<=127 ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

dm::uint16 CStringRef::toUint16( bool* ok )const{
	dm::uint16 rt = 0;
	// 0~65535
	if( len()>0 && len()<=5 ){
		if( isNum() ){
			int iValue = std::atoi(m_r);
			if( iValue>=0 && iValue<=65535 ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

dm::int16 CStringRef::toInt16(  bool* ok )const{
	dm::int16 rt = 0;
	// -32768 ~ 32767
	if( len()>0 && len()<=6 ){
		if( isNum() ){
			int iValue = std::atoi(m_r);
			if( iValue>=-32768 && iValue<=32767 ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

dm::uint32 CStringRef::toUint32( bool* ok )const{
	dm::uint32 rt = 0;
	// 0~4294967295
	if( len()>0 && len()<=10 ){
		if( isNum() ){
			long iValue = std::atol(m_r);
			if( iValue>=0 && ((unsigned long)iValue)<=4294967295ul ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

dm::int32 CStringRef::toInt32(  bool* ok )const{
	dm::int32 rt = 0;
	// -2147483648 ~ 2147483647
	if( len()>0 && len()<=11 ){
		if( isNum() ){
			long iValue = std::atol(m_r);
			if( iValue>=-2147483647 && iValue<=2147483647 ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

#ifndef NO_ATOLL

dm::uint64 CStringRef::toUint64( bool* ok )const{
	dm::uint64 rt = 0;
	//
	if( len()>0 ){
		if( isNum() ){
			long long iValue = std::atoll(m_r);
			if( iValue>=0 ){
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
			}
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

dm::int64 CStringRef::toInt64(  bool* ok )const{
	dm::int64 rt = 0;
	//
	if( len()>0 ){
		if( isNum() ){
			long long iValue = std::atoll(m_r);
				rt = iValue;
				if( ok )
					*ok = true;
				return rt;
		}
	}

	if( ok )
		*ok = false;

	return rt;
}

#endif

dm::float32 CStringRef::toFloat32( bool* ok )const{
	dm::float32 rt = 0;
	if( len()>0 ){
		if( isNum() ){
			rt = (dm::float32)std::atof(m_r);
			if( ok )
				*ok = true;
			return rt;
		}
	}

	if( ok )
		*ok = false;
	return rt;
}

dm::float64 CStringRef::toFloat64( bool* ok )const{
	dm::float64 rt = 0;
	if( len()>0 ){
		if( isNum() ){
			rt = std::atof(m_r);
			if( ok )
				*ok = true;
			return rt;
		}
	}

	if( ok )
		*ok = false;
	return rt;
}

dm::uint8 CStringRef::getHex( int pos )const{
	if( pos<0 || pos>=len() )
		return 0;
	if( m_r[pos]>='0' && m_r[pos]<='9' )
		return m_r[pos] - '0';
	if( m_r[pos]>='a' && m_r[pos]<='f' )
		return m_r[pos] - 'a' + 10;
	if( m_r[pos]>='A' && m_r[pos]<='F' )
		return m_r[pos] - 'A' + 10;
	return 0;
}

int CStringRef::getHexes( const int& len,dm::uint8* buf,const int& size )const{
	if( !isHex() || size<=0 )
		return -1;
	int p = 0;
	for( int i=0;i<len;++i ){
		if( 0==(i%2) ){
			buf[p] = getHex(i);
		}else{
			buf[p] <<= 4;
			buf[p] |= getHex(i);

			++p;
			if( p>size )
				return -2;
		}
	}

	if( len%2 )
		return p + 1;
	else
		return p;
}

void CStringRef::dump( char* buf )const{
	int l = len();
	if( l<0 )
		l = 0;

	buf[l] = '\0';
	--l;
	for( ;l>=0;--l )
		buf[l] = m_r[l];
}

bool CStringRef::dump( char* buf,int size )const{
	if( buf==NULL || size<=0 )
		return false;

	int l = len();
	if( size< l+1 )
		return false;

	dump(buf);
	return true;
}

bool CStringRef::dump( char* buf,int size,int start )const{
	if( buf==NULL || size<=0 )
		return false;

	int l = len();
	if( start<0 || start>=l )
		return false;

	if( size< l-start )
		return false;

	for(;;++start,++buf){
		*buf = m_r[start];
		if( *buf=='\0' )
			break;
	}

	return true;
}

bool CStringRef::dump( char* buf,int size,int start,int num )const{
	if( buf==NULL || size<=0 || start<0 || num<0 || size<=num )
		return false;

	if( start+num>len() )
		return false;

	for( ;num>0;--num,++start,++buf ){
		*buf = m_r[start];
	}
	*buf = '\0';

	return true;
}

/**
 * 复制部分可复制的字符串
 * @param buf
 * @param maxNum 最多字符长度
 * @return 是否有内容被复制
 */
bool CStringRef::dumpSome( char* buf,int maxNum )const{
	if( buf==NULL || maxNum<1 )
		return false;

	--maxNum;
	int l = len();
	if( l<0 )
		maxNum = 0;
	else	if( l<maxNum )
		maxNum = l;

	for( l=0;l<maxNum;++l )
		buf[l] = m_r[l];
	buf[maxNum] = '\0';
	return true;
}

bool CStringRef::dumpAutoMalloc( char* *pBuf )const{
	if(*pBuf)
		delete [] (*pBuf);
	int l = len();
	if( l>0 ){
		*pBuf = new char[l+1];
		if( (*pBuf)==NULL )
			return false;

		dump(*pBuf);
	}else{
		*pBuf = NULL;
	}

	return true;
}

bool CStringRef::isStartWith( const char* str,int num )const{
	if( str==NULL || num<=0 || len()<num )
		return false;
	for( int p=0;p<num;++p ){
		if( str[p]!=m_r[p] )
			return false;
	}
	return true;
}

bool CStringRef::isEndWith( const char* str,int num )const{
	if( str==NULL || num<=0 )
		return false;
	int l = len();
	if( l<num )
		return false;
	l -= num;
	for( int p=0;p<num;++p ){
		if( str[p]!=m_r[l+p] )
			return false;
	}

	return true;
}

/**
 * 跳过skip个字符后，查找下一个字符c的索引
 * @param c
 * @param skip
 * @return 返回c的索引，含skip的个数
 */
int CStringRef::nextChar( const char& c,int skip )const{
	if( skip<0 )
		return -1;	// 参数错误

	int l = len();
	if( skip>=l )
		return -1;	// 参数错误：跳过的字符个数大于字符串长度

	for(;skip<l;++skip ){
		if( m_r[skip]==c )
			return skip;
	}

	return -1;
}

/**
 * 跳过skip个字符后，查找下一个非字符c的索引
 * @param c
 * @param skip
 * @return 返回c的索引，含skip的个数
 */
int CStringRef::nextNoneChar( const char& c,int skip )const{
	if( skip<0 )
		return -1;

	int l = len();
	if( l<=skip )
		return -1;

	for(;skip<l;++skip ){
		if( m_r[skip]!=c )
			return skip;
	}

	return -1;
}

/**
 * 查找包含任意字符
 * @param cs 要查找的任意字符串中的字符
 * @param skip 跳过的字符个数
 * @return
 */
int CStringRef::nextChars( const char* cs,int skip )const{
	if( skip<0 )
		return -1;

	int l = len();
	if( l<=skip )
		return -1;

	CStringRef rcs(cs);
	if( rcs.len()<=0 )
		return -1;

	for(;skip<l;++skip ){
		if( rcs.nextChar(m_r[skip])!=-1 )
			return skip;
	}

	return -1;
}

/**
 * 查找包含非任意字符
 * @param cs 要查找的非任意字符串中的字符
 * @param skip 跳过的字符个数
 * @return
 */
int CStringRef::nextNoneChars( const char* cs,int skip )const{
	if( skip<0 )
		return -1;

	int l = len();
	if( l<=skip )
		return -1;
	CStringRef rcs(cs);
	if( rcs.len()<=0 )
		return -1;

	for(;skip<l;++skip ){
		if( rcs.nextChar(m_r[skip])==-1 )
			return skip;
	}

	return -1;
}

/**
 * 查找区间内任意字符
 * @param cstart 起始字符
 * @param cend 结束字符
 * @param skip 跳过的字符个数
 * @return
 */
int CStringRef::nextChars( const char& cstart,const char& cend,int skip )const{
	if( cstart>cend )
		return -1;

	if( skip<0 )
		return -1;

	int l = len();
	if( l<=skip )
		return -1;

	for(;skip<l;++skip ){
		if( m_r[skip]>=cstart && m_r[skip]<=cend )
			return skip;
	}

	return -1;
}

/**
 * 查找非区间的字符
 * 比如查找非['a','z']中的字符
 * @param cstart 起始字符
 * @param cend 结束字符
 * @param skip
 * @return
 */
int CStringRef::nextNoneChars( const char& cstart,const char& cend,int skip )const{
	if( cstart>cend )
		return -1;

	if( skip<0 )
		return -1;

	int l = len();
	if( l<=skip )
		return -1;

	for(;skip<l;++skip ){
		if( m_r[skip]<cstart || m_r[skip]>cend )
			return skip;
	}

	return -1;
}

/**
 * 反向查找第一个字符c,跳过skip个字符
 * @param c
 * @param skip 指定的位置
 * @return
 */
int CStringRef::lastChar( const char& c,int skip )const{
	if( skip<0 )
		return -1;

	int p = len() - skip - 1;

	while( p>=0 ){
		if( m_r[p]==c )
			return p;
		--p;
	}

	return -1;
}

int CStringRef::lastNoneChar( const char& c,int skip )const{
	if( skip<0 )
		return -1;
	int p = len() - skip -1;

	while( p>=0 ){
		if( m_r[p]!=c )
			return p;
		--p;
	}

	return -1;
}

int CStringRef::lastChars( const char* cs,int skip )const{
	if( skip<0 )
		return -1;

	CStringRef rcs(cs);
	if( rcs.len()<=0 )
		return -1;

	int p = len() - skip -1;
	while( p>=0 ){
		if( rcs.nextChar(m_r[p])!=-1 )
			return p;
		--p;
	}

	return -1;
}

int CStringRef::lastNoneChars( const char* cs,int skip )const{
	if( skip<0 )
		return -1;

	CStringRef rcs(cs);
	if( rcs.len()<=0 )
		return -1;

	int p = len() - skip -1;
	while( p>=0 ){
		if( rcs.nextChar(m_r[p])==-1 )
			return p;
		--p;
	}

	return -1;
}

int CStringRef::lastChars( const char& cstart,const char& cend,int skip )const{
	if( skip<0 )
		return -1;

	if( cstart>cend )
		return -1;

	int p = len() - skip -1;
	while( p>=0 ){
		if( m_r[p]>=cstart && m_r[p]<=cend )
			return p;
		--p;
	}

	return -1;
}

int CStringRef::lastNoneChars( const char& cstart,const char& cend,int skip )const{
	if( skip<0 )
		return -1;

	if( cstart>cend )
		return -1;

	int p = len() - skip -1;
	while( p>=0 ){
		if( m_r[p]<cstart || m_r[p]>cend )
			return p;
		--p;
	}

	return -1;
}

bool CStringRef::isNum()const{
	if( len()>0 && -1==nextNoneChars("0123456789.-",0) )
		return true;
	return false;
}

bool CStringRef::isHex()const{
	if( len()>0 && -1==nextNoneChars("0123456789abcdefABCDEF",0) )
		return true;
	return false;
}

bool CStringRef::isAlaphas()const{
	if( len()>0 && -1==nextNoneChars("0123456789abcdefABCDEF",0) )
		return true;
	return false;
}

}
}
